package com.study.concurrent.B_ThreadSynchronizedBasic.h_UserMultipleConditionInLock;

import java.util.LinkedList;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by 赵超 on 2017/3/23.
 * 数据缓冲类 被生产者和消费者共享
 */
public class Buffer {
    /**
     * 存放共享数据
     */
    private LinkedList<String> buffer;
    /**
     * 存放buffer的长度
     */
    private int maxSize;
    /**
     * 用来对 修改buffer的代码块 进行控制
     */
    private ReentrantLock lock;
    /**
     * 两个Condition属性 lines和space
     */
    private Condition lines;
    private Condition space;
    /**
     * 表明缓冲区中是否还存在数据
     */
    private boolean pendingLines;

    public Buffer(int maxSize) {
        this.maxSize = maxSize;
        buffer = new LinkedList<>();
        lock = new ReentrantLock();
        lines = lock.newCondition();
        space = lock.newCondition();
        pendingLines = true;
    }

    /**
     * 向缓冲区中存入数据
     *
     * @param line
     */
    public void insert(String line) {
        lock.lock();
        try {
            while (buffer.size() == maxSize) {
                // 缓冲区中没有空位就会调用await()方法使线程等待
                space.await();
            }
            // 缓冲区中有空位就会将数据保存到缓冲区
            buffer.offer(line);
            System.out.printf("%s : 插入一行，缓冲区大小 : %d\n",
                    Thread.currentThread().getName(), buffer.size());
            // 唤醒所有等待缓冲区中有数据的线程
            lines.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    /**
     * 获取缓冲区中的第一行
     */
    public String get() {
        String line = null;
        lock.lock();
        try {
            while (buffer.size() == 0 && hasPendingLines()) {
                System.out.println("------------");
                // 缓冲区为空
                lines.await();
            }
            if (hasPendingLines()) {
                // 取出第一条数据
                line = buffer.poll();
                System.out.printf("%s : 读出一行，缓冲区大小 : %d\n",
                        Thread.currentThread().getName(), buffer.size());
                space.signalAll();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
        return line;
    }

    public void setPendingLines(boolean pendingLines) {
        this.pendingLines = pendingLines;
    }

    /**
     * 查看是否还有数据行
     */
    public boolean hasPendingLines() {
        System.out.println(pendingLines);
        return pendingLines || buffer.size() > 0;
    }
}
